﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace Qero.ChartPoint
{
    class BaseUnit
    {

#region ::Enumerators::
        public enum FolderType
        {
            RootFolder = 0,
            ViewsFolder = 1,
            DBFolder = 2
        }
#endregion ::Enumerators::

#region ::Constants::

        public static string ARRSep { get { return ";"; } }

        public static string LADirectory { get { return Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); } }

        public static string DBDefaultPath { get { return Path.Combine(AppDirectory(FolderType.DBFolder), Properties.Resources.DBFileName); } }

#endregion ::Constants::

        public static string AppDirectory() { return AppDirectory(FolderType.RootFolder); }
        public static string AppDirectory(FolderType isType)
        {
            string appDirectory = Path.Combine(LADirectory, Properties.Resources.AppName);

            switch (isType)
            {
                case FolderType.ViewsFolder:
                    appDirectory = Path.Combine(appDirectory, Properties.Resources.ViewsDirectory);
                    break;
                case FolderType.DBFolder:
                    appDirectory = Path.Combine(appDirectory, Properties.Resources.DBDirectory);
                    break;
                default:
                    break;
            }

            GetDirectory(appDirectory);

            return appDirectory;
        }

        /// <summary> Проверка существования директории по заданному пути с созданием
        /// </summary>
        /// <param name="isPath"></param>
        public static void GetDirectory(string isPath)
        {
            if (!Directory.Exists(isPath)) Directory.CreateDirectory(isPath);
        }

        /// <summary> Увеличение размерности массива до заданной величины newLength.
        /// </summary>
        /// <param name="inArray">исходный массив</param>
        /// <param name="newLength">новая размерность массива</param>
        /// <returns>расширенный массив типа Array</returns>
        public static Array ExpandArray(Array inArray, int newLength)
        {
            Array outArray = Array.CreateInstance(inArray.GetType().GetElementType(), newLength);
            inArray.CopyTo(outArray, 0);

            return outArray;
        }

        public static Guid[] OptionsUid(string optValue)
        {
            List<Guid> outArray = new List<Guid>();

            string[] strArray = OptionsStr(optValue);

            foreach (string loopStr in strArray)
            {
                Guid loopUid = new Guid();

                if (Guid.TryParse(loopStr, out loopUid))
                    outArray.Add(loopUid);
            }

            return outArray.ToArray();
        }

        /// <summary> Преобразование строки значений разделенных точкой с запятой (";") в массив
        /// Процедура обратная OptValue(optArray)
        /// </summary>
        /// <param name="optValue">строка с массивом значений, разделенных точкой с запятой (";")</param>
        public static string[] OptionsStr(string optValue)
        {
            string[] sepSymb = new string[] { ARRSep, "\n", "," }, isOptions = new string[] { };

            if (!string.IsNullOrEmpty(optValue)) isOptions = optValue.Split(sepSymb, StringSplitOptions.RemoveEmptyEntries);

            return isOptions;
        }

        /// <summary> Преобразование массива Guid'ов в строку с разделителем "точка с запятой"
        /// </summary>
        /// <param name="optArray">массив Guid'ов</param>
        public static string StringFrOpt(Guid[] optArray)
        {
            return string.Join(ARRSep, optArray);
        }

        /// <summary> Преобразование массива строк в строку значений разделенных точкой с запятой (";").
        /// Процедура обратная GetOptis(optValue)
        /// </summary>
        /// <param name="optArray">массив строк</param>
        public static string StringFrOpt(string[] optArray)
        {
            return StringFrOpt(optArray, ARRSep);
        }

        /// <summary> Преобразование массива строк в строку значений разделенных требуемым символом
        /// </summary>
        /// <param name="optArray">массив строк</param>
        /// <param name="sepSymb">символ разделителя</param>
        public static string StringFrOpt(string[] optArray, string sepSymb)
        {
            return string.Join(sepSymb, optArray);
        }

        /// <summary> Возврат дочернего контрола из дерева подчиненных элементов XAML-формы
        /// </summary>
        /// <typeparam name="T">запрашиваемый тип контрола</typeparam>
        /// <param name="parent">родительский контрол по отношению к запрашиваемому</param>
        /// <param name="childName">имя подчиненного элемента запрашиваемого типа (если имя не указано - будет возращен ближайший подчиненный контрол запрошенного типа)</param>
        /// <returns>возврат элемента заданного типа</returns>
        public static T GetChildControl<T>(DependencyObject parent, string childName)
            where T : DependencyObject
        {
            // Confirm parent and childName are valid.  
            if (parent == null) return null;

            T foundChild = null;

            int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
            for (int i = 0; i < childrenCount; i++)
            {
                var child = VisualTreeHelper.GetChild(parent, i);
                // Проверка: является ли полученный дочерний элемент элементом запрашиваемого типа
                T childType = child as T;
                if (childType == null)
                {
                    // если не является - рекурсивно обходим дерево элементов от полученного дочернего элемента далее
                    foundChild = GetChildControl<T>(child, childName);

                    // Проверка: найден ли дочерний элемент в результате рекурсивного обхода - если найден, то прерываем цикл.  
                    if (foundChild != null) break;
                }
                else if (!string.IsNullOrEmpty(childName))
                {
                    var frameworkElement = child as FrameworkElement;
                    // If the child's name is set for search 
                    if (frameworkElement != null && frameworkElement.Name == childName)
                    {
                        // if the child's name is of the request name 
                        foundChild = (T)child;
                        break;
                    }
                    else
                    {
                        foundChild = GetChildControl<T>(child, childName);

                        if (foundChild != null) break;
                    }
                }
                else
                {
                    // child element found. 
                    foundChild = (T)child;
                    break;
                }
            }

            return foundChild;
        }

        /// <summary> Возврат родительского контрола из вышестоящих элементов XAML-формы
        /// </summary>
        /// <typeparam name="T">запрашиваемый тип контрола</typeparam>
        /// <param name="elchild">визуальный элемент (контрол) - дочерний, по отношению к запрашиваемому</param>
        /// <param name="parentName">имя родительского элемента запрашиваемого типа (если имя не указано - будет возращен ближайший родительский контрол запрошенного типа)</param>
        /// <returns></returns>
        public static T GetParentControl<T>(DependencyObject elchild, string parentName)
            where T : DependencyObject
        {
            if (elchild == null) return null;

            T foundParent = null;

            bool isLoop = true;

            var tmpChild = elchild;

            while (isLoop)
            {
                var currParent = VisualTreeHelper.GetParent(tmpChild);

                if (currParent != null)
                {
                    T parType = currParent as T;

                    if (parType == null)
                        tmpChild = currParent;
                    else if ((parType != null) && (string.IsNullOrEmpty(parentName)))
                    {
                        foundParent = (T)currParent;
                        isLoop = false;
                    }
                    else if ((parType != null) && (!string.IsNullOrEmpty(parentName)))
                    {
                        var frameworkElement = foundParent as FrameworkElement;
                        if (frameworkElement != null && frameworkElement.Name == parentName)
                        {
                            foundParent = (T)currParent;
                            isLoop = false;
                        }
                    }
                }
                else
                    isLoop = false;
            }

            return foundParent;
        }
    }
}
